/*
 * Copyright 2006 Abdulla G. Abdurakhmanov (abdulla.abdurakhmanov@gmail.com).
 * 
 * Licensed under the GPL, Version 2 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.gnu.org/copyleft/gpl.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * With any your questions welcome to my e-mail 
 * or blog at http://abdulla-a.blogspot.com.
 */

package org.ofsm.creator;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;
import java.io.ByteArrayOutputStream;
import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.util.Enumeration;

import javax.swing.AbstractListModel;
import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;

import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import org.jgraph.JGraph;

import org.jgraph.event.GraphSelectionEvent;
import org.jgraph.event.GraphSelectionListener;

import org.ofsm.IState;
import org.ofsm.impl.Event;
import org.ofsm.impl.FileFiniteStateMachineBaseModel;
import org.ofsm.impl.FileFiniteStateMachineModel;
import org.ofsm.impl.State;
import org.ofsm.impl.StateTransition;

public class CreatorFrame extends JFrame {
    private JMenuBar menuBar = new JMenuBar();
    private JMenu menuFile = new JMenu();
    private JMenuItem menuFileExit = new JMenuItem();
    private JMenu menuHelp = new JMenu();
    private JMenuItem menuHelpAbout = new JMenuItem();
    private BorderLayout borderLayout1 = new BorderLayout();
    private JTabbedPane tabbedPanel = new JTabbedPane();
    private JPanel eventsPanel = new JPanel();
    private JPanel statesPanel = new JPanel();
    private JPanel diagramPanel = new JPanel();
    private JPanel tablePanel = new JPanel();
    private BorderLayout eventsPanelLayout = new BorderLayout();
    private JScrollPane eventsScrollPane = new JScrollPane();
    private JPanel viewEventPanel = new JPanel();
    private JList lstEvents = new JList();
    private JLabel lblEventName = new JLabel();
    private JLabel lblEventClassName = new JLabel();
    private JPanel eventButtonsPanel = new JPanel();
    private JButton btnAddEvent = new JButton();
    private JButton btnEditEvent = new JButton();
    private JButton btnDeleteEvent = new JButton();
    private JTextField edtEventName = new JTextField();
    private JScrollPane statesScrollPanel = new JScrollPane();
    private BorderLayout statesPanelLayout = new BorderLayout();
    private JPanel viewStatePanel = new JPanel();
    private JList lstStates = new JList();
    private JLabel lblStateName = new JLabel();
    private JTextField edtStateName = new JTextField();
    private JLabel lblStateClassName = new JLabel();
    private JPanel stateButtonsPanel = new JPanel();
    private JButton btnAddState = new JButton();
    private JButton btnEditState = new JButton();
    private JButton btnDeleteState = new JButton();
    private JTextField edtEventClassName = new JTextField();
    private JTextField edtStateClassName = new JTextField();
    private BorderLayout diagramPanelLayout = new BorderLayout();
    private JSplitPane diagramSplitter = new JSplitPane();
    private JScrollPane diagramScrollPanel = new JScrollPane();
    private JPanel diagramControlPanel = new JPanel();
    private JGraph diagramGraph = new JGraph();
    private BorderLayout borderLayout2 = new BorderLayout();
    private JSplitPane diagramCtrlPanelSplitter = new JSplitPane();
    private JTable tblDiagramItemProperties = new JTable();
    private JPanel toolboxPanel = new JPanel();
    private JMenuItem menuOpenItem = new JMenuItem();
    private JMenuItem menuSaveItem = new JMenuItem();
    private JPanel xmlModelPanel = new JPanel();
    private JScrollPane jScrollPane2 = new JScrollPane();
    private JPanel jPanel3 = new JPanel();
    private BorderLayout borderLayout3 = new BorderLayout();
    private JButton btnRefreshXmlModel = new JButton();
    private JTextArea txtXMLModel = new JTextArea();
    private JButton btnAddTransition = new JButton();
    private JButton btnSetInitialState = new JButton();
    private JButton btnRemoveTransition = new JButton();
    private JScrollPane tableScrollPanel = new JScrollPane();
    private JTable tblStates = new JTable();
    private BorderLayout borderLayout4 = new BorderLayout();
    private GridBagLayout gridBagLayout1 = new GridBagLayout();
    private GridBagLayout gridBagLayout2 = new GridBagLayout();
    private GridBagLayout gridBagLayout3 = new GridBagLayout();

    public CreatorFrame() {
        try {
            jbInit();
            jbInitEx();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void jbInit() throws Exception {
        this.setJMenuBar( menuBar );
        this.getContentPane().setLayout(borderLayout1);
        this.setSize(new Dimension(539, 458));
        this.setTitle("Open Finite State Machine Creator");
        this.setFont(new Font("Tahoma", 0, 12));
        this.addWindowListener(new WindowAdapter() {
                    public void windowOpened(WindowEvent e) {
                        this_windowOpened(e);
                    }
                });
        menuFile.setText( "File" );
        menuFileExit.setText( "Exit" );
        menuFileExit.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent ae ) { fileExit_ActionPerformed( ae ); } } );
        menuHelp.setText( "Help" );
        menuHelpAbout.setText( "About" );
        menuHelpAbout.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent ae ) { helpAbout_ActionPerformed( ae ); } } );
        tabbedPanel.addChangeListener(new ChangeListener() {
                    public void stateChanged(ChangeEvent e) {
                        tabbedPanel_stateChanged(e);
                    }
                });
        eventsPanel.setFont(new Font("Tahoma", 0, 12));
        eventsPanel.setLayout(eventsPanelLayout);
        statesPanel.setFont(new Font("Tahoma", 0, 12));
        statesPanel.setLayout(statesPanelLayout);
        diagramPanel.setFont(new Font("Tahoma", 0, 12));
        diagramPanel.setLayout(diagramPanelLayout);
        tablePanel.setFont(new Font("Tahoma", 0, 12));
        tablePanel.setLayout(borderLayout4);
        viewEventPanel.setSize(new Dimension(390, 50));
        viewEventPanel.setPreferredSize(new Dimension(10, 140));
        viewEventPanel.setLayout(gridBagLayout1);
        lstEvents.addListSelectionListener(new ListSelectionListener() {
                    public void valueChanged(ListSelectionEvent e) {
                        lstEvents_valueChanged(e);
                    }
                });
        lblEventName.setText("Event name:");
        lblEventClassName.setText("Event class name:");
        eventButtonsPanel.setPreferredSize(new Dimension(10, 30));
        btnAddEvent.setText("Add");
        btnAddEvent.setPreferredSize(new Dimension(80, 23));
        btnAddEvent.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnAddEvent_actionPerformed(e);
                    }
                });
        btnEditEvent.setText("Edit");
        btnEditEvent.setPreferredSize(new Dimension(80, 23));
        btnEditEvent.setEnabled(false);
        btnEditEvent.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnEditEvent_actionPerformed(e);
                    }
                });
        btnDeleteEvent.setText("Delete");
        btnDeleteEvent.setPreferredSize(new Dimension(80, 23));
        btnDeleteEvent.setEnabled(false);
        btnDeleteEvent.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnDeleteEvent_actionPerformed(e);
                    }
                });
        edtEventName.setEditable(false);
        viewStatePanel.setPreferredSize(new Dimension(10, 140));
        viewStatePanel.setLayout(gridBagLayout2);
        lstStates.addListSelectionListener(new ListSelectionListener() {
                    public void valueChanged(ListSelectionEvent e) {
                        lstStates_valueChanged(e);
                    }
                });
        lblStateName.setText("State name:");
        edtStateName.setEditable(false);
        lblStateClassName.setText("State class name:");
        stateButtonsPanel.setPreferredSize(new Dimension(10, 40));
        btnAddState.setText("Add");
        btnAddState.setPreferredSize(new Dimension(80, 23));
        btnAddState.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnAddState_actionPerformed(e);
                    }
                });
        btnEditState.setText("Edit");
        btnEditState.setPreferredSize(new Dimension(80, 23));
        btnEditState.setEnabled(false);
        btnEditState.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnEditState_actionPerformed(e);
                    }
                });
        btnDeleteState.setText("Delete");
        btnDeleteState.setPreferredSize(new Dimension(80, 23));
        btnDeleteState.setEnabled(false);
        btnDeleteState.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnDeleteState_actionPerformed(e);
                    }
                });
        edtEventClassName.setEditable(false);
        edtStateClassName.setEditable(false);
        diagramSplitter.setDividerLocation(-1);
        diagramControlPanel.setLayout(borderLayout2);
        diagramGraph.addGraphSelectionListener(new GraphSelectionListener() {
                    public void valueChanged(GraphSelectionEvent e) {
                        diagramGraph_valueChanged(e);
                    }
                });
        diagramCtrlPanelSplitter.setOrientation(JSplitPane.VERTICAL_SPLIT);
        tblDiagramItemProperties.setPreferredSize(new Dimension(0, 80));
        toolboxPanel.setPreferredSize(new Dimension(10, 180));
        toolboxPanel.setLayout(gridBagLayout3);
        menuOpenItem.setText("Open ...");
        menuOpenItem.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        menuOpenItem_actionPerformed(e);
                    }
                });
        menuSaveItem.setText("Save ...");
        menuSaveItem.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        menuSaveItem_actionPerformed(e);
                    }
                });
        xmlModelPanel.setLayout(borderLayout3);
        jPanel3.setPreferredSize(new Dimension(10, 30));
        btnRefreshXmlModel.setText("Generate model (Refresh)");
        btnRefreshXmlModel.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnRefreshXmlModel_actionPerformed(e);
                    }
                });
        txtXMLModel.setEditable(false);
        btnAddTransition.setText("Add transition");
        btnAddTransition.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnAddTransition_actionPerformed(e);
                    }
                });
        btnSetInitialState.setText("Set to initial state");
        btnSetInitialState.setEnabled(false);
        btnSetInitialState.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnSetInitialState_actionPerformed(e);
                    }
                });
        btnRemoveTransition.setText("Remove transition");
        btnRemoveTransition.setEnabled(false);
        btnRemoveTransition.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        btnRemoveTransition_actionPerformed(e);
                    }
                });
        menuFile.add(menuOpenItem);
        menuFile.add(menuSaveItem);
        menuFile.add(menuFileExit);
        menuBar.add(menuFile);
        menuHelp.add(menuHelpAbout);
        menuBar.add(menuHelp);
        eventsScrollPane.getViewport().add(lstEvents, null);
        eventsPanel.add(eventsScrollPane, BorderLayout.CENTER);
        eventsPanel.add(viewEventPanel, BorderLayout.SOUTH);
        viewEventPanel.add(lblEventName, 
                           new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, 
                                                  new Insets(5, 5, 0, 5), 460, 
                                                  0));
        viewEventPanel.add(edtEventName, 
                           new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, 
                                                  new Insets(0, 5, 0, 5), 512, 
                                                  0));
        viewEventPanel.add(lblEventClassName, 
                           new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, 
                                                  new Insets(0, 5, 0, 5), 431, 
                                                  0));
        viewEventPanel.add(edtEventClassName, 
                           new GridBagConstraints(0, 3, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, 
                                                  new Insets(0, 5, 0, 5), 512, 
                                                  0));
        eventButtonsPanel.add(btnAddEvent, null);
        eventButtonsPanel.add(btnEditEvent, null);
        eventButtonsPanel.add(btnDeleteEvent, null);
        viewEventPanel.add(eventButtonsPanel, 
                           new GridBagConstraints(0, 4, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
                                                  new Insets(0, 5, 13, 5), 509, 
                                                  0));
        tabbedPanel.addTab("Events", eventsPanel);
        statesScrollPanel.getViewport().add(lstStates, null);
        statesPanel.add(statesScrollPanel, BorderLayout.CENTER);
        viewStatePanel.add(lblStateName, 
                           new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, 
                                                  new Insets(5, 5, 0, 5), 462, 
                                                  0));
        viewStatePanel.add(edtStateName, 
                           new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, 
                                                  new Insets(0, 5, 0, 5), 512, 
                                                  0));
        viewStatePanel.add(lblStateClassName, 
                           new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, 
                                                  new Insets(0, 5, 0, 5), 433, 
                                                  0));
        viewStatePanel.add(edtStateClassName, 
                           new GridBagConstraints(0, 3, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, 
                                                  new Insets(0, 5, 0, 5), 512, 
                                                  0));
        stateButtonsPanel.add(btnAddState, null);
        stateButtonsPanel.add(btnEditState, null);
        stateButtonsPanel.add(btnDeleteState, null);
        viewStatePanel.add(stateButtonsPanel, 
                           new GridBagConstraints(0, 4, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, 
                                                  new Insets(0, 5, 3, 5), 509, 
                                                  0));
        statesPanel.add(viewStatePanel, BorderLayout.SOUTH);
        tabbedPanel.addTab("States", statesPanel);
        diagramScrollPanel.getViewport().add(diagramGraph, null);
        diagramSplitter.add(diagramScrollPanel, JSplitPane.LEFT);
        diagramCtrlPanelSplitter.add(tblDiagramItemProperties, JSplitPane.BOTTOM);
        toolboxPanel.add(btnAddTransition, 
                         new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, 
                                                new Insets(5, 5, 0, 5), 19, 
                                                0));
        toolboxPanel.add(btnSetInitialState, 
                         new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, 
                                                new Insets(0, 5, 0, 5), 5, 0));
        toolboxPanel.add(btnRemoveTransition, 
                         new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, 
                                                new Insets(0, 5, 96, 5), 0, 
                                                0));
        diagramCtrlPanelSplitter.add(toolboxPanel, JSplitPane.TOP);
        diagramControlPanel.add(diagramCtrlPanelSplitter, BorderLayout.CENTER);
        diagramSplitter.add(diagramControlPanel, JSplitPane.RIGHT);
        diagramPanel.add(diagramSplitter, BorderLayout.CENTER);
        tabbedPanel.addTab("Diagram", diagramPanel);
        tableScrollPanel.getViewport().add(tblStates, null);
        tablePanel.add(tableScrollPanel, BorderLayout.CENTER);
        tabbedPanel.addTab("Table", tablePanel);
        jScrollPane2.getViewport().add(txtXMLModel, null);
        xmlModelPanel.add(jScrollPane2, BorderLayout.CENTER);
        jPanel3.add(btnRefreshXmlModel, null);
        xmlModelPanel.add(jPanel3, BorderLayout.SOUTH);
        tabbedPanel.addTab("Model as XML", xmlModelPanel);
        this.getContentPane().add(tabbedPanel, BorderLayout.CENTER);
    }

    void fileExit_ActionPerformed(ActionEvent e) {
        System.exit(0);
    }

    void helpAbout_ActionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(this, new AboutBoxPanel(), "About", JOptionPane.PLAIN_MESSAGE);
    }

    private void jbInitEx() {
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        ImageIcon img = new ImageIcon(getClass().getResource("images/logo.gif"));
        setIconImage(img.getImage());        
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frameSize = getSize();
        if (frameSize.height > screenSize.height) {
            frameSize.height = screenSize.height;
        }
        if (frameSize.width > screenSize.width) {
            frameSize.width = screenSize.width;
        }
        setSize(frameSize);
        setLocation( ( screenSize.width - frameSize.width ) / 2, ( screenSize.height - frameSize.height ) / 2 );
        setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        
        tabbedPanel.setIconAt(0,new ImageIcon(getClass().getResource("images/events.gif")));
        tabbedPanel.setIconAt(1,new ImageIcon(getClass().getResource("images/states.gif")));
        tabbedPanel.setIconAt(2,new ImageIcon(getClass().getResource("images/diagram.gif")));
        tabbedPanel.setIconAt(3,new ImageIcon(getClass().getResource("images/table.gif")));
        
        model.setSafeUnmarshallingMode(true);
        setEventsListModel();
        setStatesListModel();
        setDiagramModel();
        setTableModel();
    }
        
    private FileFiniteStateMachineModel model = new FileFiniteStateMachineModel();
    private StateDiagramManager stateDiagramMgr = new StateDiagramManager(model, diagramGraph);
    private class OfspFileFilter extends FileFilter {
        public boolean accept(File f) {
            if(f.isDirectory())
                return true;
            if(f.getName().contains(".ofsm.xml"))
                return true;
            else
                return false;
        }

        public String getDescription() {
            return "OpenFiniteStateMachine file format (*.ofsm.xml)";
        }        
    }

    private void menuOpenItem_actionPerformed(ActionEvent e) {    
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(new OfspFileFilter());
        int result = chooser.showOpenDialog(this);
        if(result == JFileChooser.APPROVE_OPTION) {            
            try {
                model.unmarshal(new FileInputStream(chooser.getSelectedFile()));
            } 
            catch (Exception ex) {
                JOptionPane.showMessageDialog(this,ex.getMessage(),"Error when opening file...",JOptionPane.ERROR_MESSAGE);
            }
        }
        updateVisualization();
    }

    private void updateVisualization() {
        lstEvents.updateUI();
        lstStates.updateUI();
        updateEventView();
        updateStateView();
        setDiagramModel();
        diagramGraph.updateUI();
        //tblStates.updateUI();
        setTableModel();
    }

    private void setEventsListModel() {
        lstEvents.setModel(new AbstractListModel() {            
           
            public int getSize()  {
                int result = model.getEventInfos().size();
                return result;
            }

            public Object getElementAt(int index) {
                int idx = 0;
                for(FileFiniteStateMachineBaseModel.EventInfo item: model.getEventInfos()) {
                    if(idx++ >=index)
                        return item;
                    //lstEvents.add(item.getValue().getEvent().getName(),item.getValue());
                }            
                return null;
            }
        });
    }

    private void setStatesListModel() {
        lstStates.setModel(new AbstractListModel() {            
           
            public int getSize()  {
                int result = model.getStateInfos().size();
                return result;
            }

            public Object getElementAt(int index) {
                int idx = 0;
                for(FileFiniteStateMachineBaseModel.StateInfo item: model.getStateInfos()) {
                    if(idx++ >=index)
                        return item;
                }            
                return null;
            }
        });
    
    }

    private void setDiagramModel() {
        stateDiagramMgr.setupModel();        
    }

    private void lstEvents_valueChanged(ListSelectionEvent e) {
        updateEventView();
    }

    private void updateEventView() {
        if(lstEvents.getSelectedValue()!=null) {
            FileFiniteStateMachineBaseModel.EventInfo eventInfo = 
                (FileFiniteStateMachineBaseModel.EventInfo)lstEvents.getSelectedValue();
            edtEventName.setText(eventInfo.getEvent().getName());
            if(eventInfo.getClassName()!=null)
                edtEventClassName.setText(eventInfo.getClassName());
            else
                edtEventClassName.setText("");
            btnEditEvent.setEnabled(true);
            btnDeleteEvent.setEnabled(true);
        }
        else {
            edtEventName.setText("");
            edtEventClassName.setText("");
            btnEditEvent.setEnabled(false);
            btnDeleteEvent.setEnabled(false);
        }
    }

    private void lstStates_valueChanged(ListSelectionEvent e) {
        updateStateView();    
    }

    private void updateStateView() {
        if(lstStates.getSelectedValue()!=null) {
            FileFiniteStateMachineBaseModel.StateInfo stateInfo = 
                (FileFiniteStateMachineBaseModel.StateInfo)lstStates.getSelectedValue();
            edtStateName.setText(stateInfo.getState().getName());
            if(stateInfo.getClassName()!=null)
                edtStateClassName.setText(stateInfo.getClassName());
            else
                edtStateClassName.setText("");
            btnEditState.setEnabled(true);
            btnDeleteState.setEnabled(true);                
        }
        else {
            edtStateName.setText("");
            edtStateClassName.setText("");
            btnEditState.setEnabled(false);
            btnDeleteState.setEnabled(false);
        }
    }

    private void btnAddEvent_actionPerformed(ActionEvent e) {
        ObjectEditorDialog objDialog = new ObjectEditorDialog(this,"Create new event...",true);
        boolean tryingToShow = false;
        do {
            tryingToShow = false;
            objDialog.setVisible(true);
            if(objDialog.isApproved()) {
                try {
                    FileFiniteStateMachineBaseModel.EventInfo eventInfo = 
                        model.new EventInfo();
                    Event event = new Event();
                    event.setName(objDialog.getName());
                    eventInfo.setEvent(event);
                    eventInfo.setClassName(objDialog.getClassName());
                    model.addEventInfo(eventInfo);
                }
                catch(Exception ex) {
                    JOptionPane.showMessageDialog(this,ex.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
                    tryingToShow = true;
                }
            }
        }
        while(tryingToShow);
        updateVisualization();
    }

    private void btnEditEvent_actionPerformed(ActionEvent e) {
        FileFiniteStateMachineBaseModel.EventInfo eventInfo = 
            (FileFiniteStateMachineBaseModel.EventInfo) lstEvents.getSelectedValue();                
        ObjectEditorDialog objDialog = new ObjectEditorDialog(this,"Edit event",true);
        objDialog.setName(eventInfo.getEvent().getName());
        objDialog.setClassName(eventInfo.getClassName());
        boolean tryingToShow = false;
        do {
            tryingToShow = false;
            objDialog.setVisible(true);
            if(objDialog.isApproved()) {
                try {
                    eventInfo.getEvent().setName(objDialog.getName());
                    eventInfo.setClassName(objDialog.getClassName());
                }
                catch(Exception ex) {
                    JOptionPane.showMessageDialog(this,ex.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
                    tryingToShow = true;
                }
            }
        }
        while(tryingToShow);
        updateVisualization();    
    }

    private void btnDeleteEvent_actionPerformed(ActionEvent e) {
        FileFiniteStateMachineBaseModel.EventInfo eventInfo = 
            (FileFiniteStateMachineBaseModel.EventInfo) lstEvents.getSelectedValue();                
    
        int result = JOptionPane.showConfirmDialog(this,"Are you sure you want to delete event?","Warning",JOptionPane.YES_NO_OPTION);
        if(result==JOptionPane.YES_OPTION) {
            model.deleteEventInfo(eventInfo);
            updateVisualization();
        }
    }

    private void btnAddState_actionPerformed(ActionEvent e) {
        ObjectEditorDialog objDialog = new ObjectEditorDialog(this,"Create new state...",true);
        boolean tryingToShow = false;
        do {
            tryingToShow = false;
            objDialog.setVisible(true);
            if(objDialog.isApproved()) {
                try {
                    FileFiniteStateMachineBaseModel.StateInfo stateInfo = 
                        model.new StateInfo();
                    State state = new State();
                    state.setName(objDialog.getName());
                    stateInfo.setState(state);
                    stateInfo.setClassName(objDialog.getClassName());
                    model.addStateInfo(stateInfo);
                }
                catch(Exception ex) {
                    JOptionPane.showMessageDialog(this,ex.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
                    tryingToShow = true;
                }
            }
        }
        while(tryingToShow);
        updateVisualization();    
    }

    private void btnEditState_actionPerformed(ActionEvent e) {
        FileFiniteStateMachineBaseModel.StateInfo stateInfo = 
            (FileFiniteStateMachineBaseModel.StateInfo) lstStates.getSelectedValue();                
        ObjectEditorDialog objDialog = new ObjectEditorDialog(this,"Edit state",true);
        objDialog.setName(stateInfo.getState().getName());
        objDialog.setClassName(stateInfo.getClassName());
        boolean tryingToShow = false;
        do {
            tryingToShow = false;
            objDialog.setVisible(true);
            if(objDialog.isApproved()) {
                try {
                    stateInfo.getState().setName(objDialog.getName());
                    stateInfo.setClassName(objDialog.getClassName());
                }
                catch(Exception ex) {
                    JOptionPane.showMessageDialog(this,ex.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
                    tryingToShow = true;
                }
            }
        }
        while(tryingToShow);
        updateVisualization();    
    
    }

    private void btnDeleteState_actionPerformed(ActionEvent e) {
        FileFiniteStateMachineBaseModel.StateInfo stateInfo = 
            (FileFiniteStateMachineBaseModel.StateInfo) lstStates.getSelectedValue();                
        
        int result = JOptionPane.showConfirmDialog(this,"Are you sure you want to delete state?","Warning",JOptionPane.YES_NO_OPTION);
        if(result==JOptionPane.YES_OPTION) {
            model.deleteStateInfo(stateInfo);
            updateVisualization();
        }    
    }

    private void btnRefreshXmlModel_actionPerformed(ActionEvent e) {
        try {
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            model.marshal(output);
            txtXMLModel.setText(output.toString());
        }
        catch(Exception ex) {
            JOptionPane.showMessageDialog(this,ex.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
        }
    }

    private void this_windowOpened(WindowEvent e) {
        diagramSplitter.setDividerLocation(0.85);
    }

    private void btnAddTransition_actionPerformed(ActionEvent e) {
        TransitionEditorDialog transDialog = new TransitionEditorDialog(model, this,"Add new transition",true);
        if(diagramGraph.getSelectionCount() > 0) {
            Object[] objs = diagramGraph.getSelectionCells();
            if(objs[0] instanceof StateGraphCell)
                transDialog.selectFromState((FileFiniteStateMachineModel.StateInfo)(((StateGraphCell)objs[0]).getUserObject()));
            if(objs.length > 1 ) {
                transDialog.selectToState((FileFiniteStateMachineModel.StateInfo)(((StateGraphCell)objs[1]).getUserObject()));
            }
        }
        transDialog.setVisible(true);
        
        if(transDialog.isApproved()) {
            updateVisualization();
        }
    }

    private void btnSetInitialState_actionPerformed(ActionEvent e) {
        stateDiagramMgr.setSelectedInitialState();
        updateVisualization();
    }

    private void btnRemoveTransition_actionPerformed(ActionEvent e) {
        int result = JOptionPane.showConfirmDialog(this,"Are you sure you want to delete the transition?","Warning",JOptionPane.YES_NO_OPTION);
        if(result==JOptionPane.YES_OPTION) {    
            stateDiagramMgr.removeSelectedTransition();
            updateVisualization();
        }
    }

    private void setTableModel() {
        tblStates.setModel(new StatesTableModel(model));
        Color headerColor = Color.gray.brighter();
        tblStates.getTableHeader().setBackground(headerColor);
        JComboBox comboBox = new JComboBox();
        comboBox.addItem("...");
        for(FileFiniteStateMachineModel.StateInfo item: model.getStateInfos()) {
            comboBox.addItem(item);
        }
        Enumeration columns =  tblStates.getColumnModel().getColumns();
        int idx = 0;
        while(columns.hasMoreElements()) {
            TableColumn column = (TableColumn)columns.nextElement();
            if(idx == 0) {
                DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
                renderer.setBackground(headerColor);
                column.setCellRenderer(renderer);
            }
            else {
                column.setCellEditor(new DefaultCellEditor(comboBox));
            }
            idx++;
        }
    }

    private void tabbedPanel_stateChanged(ChangeEvent e) {
        updateVisualization();
    }

    private void diagramGraph_valueChanged(GraphSelectionEvent e) {
        if(diagramGraph.getSelectionCount() == 1) {
            Object obj = diagramGraph.getSelectionCell();
            if(obj instanceof EventGraphEdge) {
                btnRemoveTransition.setEnabled(true);
            }
            else
                btnRemoveTransition.setEnabled(false);
            if(obj instanceof StateGraphCell) {
                btnSetInitialState.setEnabled(true);
            }
            else
                btnSetInitialState.setEnabled(false);
        } 
        tblDiagramItemProperties.setModel(new StateDiagramItemTablePropertiesModel(model,diagramGraph));
        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
        renderer.setBackground(Color.gray.brighter());
        
        tblDiagramItemProperties.getColumn(tblDiagramItemProperties.getColumnName(0)).setCellRenderer(renderer);
    }

    private void menuSaveItem_actionPerformed(ActionEvent e) {
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(new OfspFileFilter());
        int result = chooser.showSaveDialog(this);
        if(result == JFileChooser.APPROVE_OPTION) {            
            try {
                String fileName  = chooser.getSelectedFile().getPath();
                if(!fileName.contains(".xml")) {
                    fileName += ".ofsm.xml";
                }
                model.marshal(new FileOutputStream(fileName));
            } 
            catch (Exception ex) {
                JOptionPane.showMessageDialog(this,ex.getMessage(),"Error when opening file...",JOptionPane.ERROR_MESSAGE);
            }
        }    
    }
}
